package org.varscape.core.reader;

import java.util.ArrayList;

// Currently (23-4-2012) we are only supporting VCF 4.0 now

//Reference:
//http://www.1000genomes.org/wiki/Analysis/Variant%20Call%20Format/vcf-variant-call-format-version-41
public abstract class AbstractVCFReader {

	protected String currentLine;
	protected ArrayList<String> currentLineTokens;

	// In all cases, missing values are specified with a dot (.).	
	
	//Chromosome: an identifier from the reference genome or an angle-bracketed ID String ("<ID>")
	// pointing to a contig in the assembly file (cf. the ##assembly line in the header).
	// All entries for a specific CHROM should form a contiguous block.
	// (String, no white-space permitted, Required).
	public final static int chrIndex = 0;

	//The reference position, with the 1st base having position 1.
	//Positions are sorted numerically, in increasing order, within each reference sequence CHROM.
	//It is permitted to have multiple records with the same POS. **********
	//Telomeres are indicated by using positions 0 or N+1, where N is the length of the corresponding chromosome or contig.
	//(Integer, Required)
	public final static int posIndex = 1;
	
	// Semi-colon separated list of unique identifiers where available.
	// If this is a dbSNP variant it is encouraged to use the rs number(s).
	// No identifier should be present in more than one data record.
	// (String, no white-space or semi-colons permitted)
	public final static int idIndex = 2;
	
	// Reference base(s): Each base must be one of A,C,G,T,N (case insensitive). Multiple bases are permitted.
	// The value in the POS field refers to the position of the first base in the String.
	// For InDels or larger structural variants, the reference String must include the base before the event (which must be reflected in the POS field).
	// (String, Required).
	public final static int refIndex = 3;
	
	// comma separated list of alternate non-reference alleles called on at least one of the samples.
	// Options are base Strings made up of the bases A,C,G,T,N, (case insensitive) or 
	// an angle-bracketed ID String (<ID>) or a breakend replacement string as described in the section on breakends.
	// If there are no alternative alleles, then the missing value should be used.
	// (String; no whitespace, commas, or angle-brackets are permitted in the ID String itself)
	public final static int altIndex = 4;		
	
	public final static int qualIndex = 5;
	
	public final static int filterIndex = 6;
	
	//5. INFO keys used for structural variants
	// ID=END: For precise variants, END is POS + length of REF allele - 1, and the for imprecise variants the corresponding best estimate.
	// ID=SVTYPE: Value should be one of DEL, INS, DUP, INV, CNV, BND. This key can be derived from the REF/ALT fields but is useful for filtering.
	// ID=SVLEN: One value for each ALT allele. Longer ALT alleles (e.g. insertions) have positive values, shorter ALT alleles (e.g. deletions) have negative values.
	// ...
	public final static int infoIndex = 7;
	
//	 FORMAT keys used for structural variants
//	 ##FORMAT=<ID=CN,Number=1,Type=Integer,Description=Copy number genotype for imprecise events>
//	 ##FORMAT=<ID=CNQ,Number=1,Type=Float,Description=Copy number genotype quality for imprecise events>
//	 ##FORMAT=<ID=CNL,Number=.,Type=Float,Description=Copy number genotype likelihood for imprecise events>
//	 ##FORMAT=<ID=MQ,Number=1,Type=Integer,Description=Phred style probability score that the variant is novel with respect to the genome's ancestor>
//	 ##FORMAT=<ID=HAP,Number=1,Type=Integer,Description=Unique haplotype identifier>
//	 ##FORMAT=<ID=AHAP,Number=1,Type=Integer,Description=Unique identifier of ancestral haplotype>
	public final static int formatIndex = 8; // if genotype data is present in the file  
	
	protected AbstractVCFReader() {
	}
	
	public String readChr() {
		return currentLineTokens.get(chrIndex);
	}
		
	public int readPos() {
		return Integer.parseInt(currentLineTokens.get(posIndex));
	}
	
	public String readID() {
		return currentLineTokens.get(idIndex);
	}
	
	public String readRef() {
		return currentLineTokens.get(refIndex);
	}
	
	public String readAlt() {
		return currentLineTokens.get(altIndex);
	}
	
	public String readOtherInfo() {
//		StringBuffer sb = new StringBuffer();
//		for (int i = altIndex + 1; i < currentLineTokens.size(); i++) {
//			sb.append(currentLineTokens.get(i));
//			if (i != currentLineTokens.size()+1) {
//				sb.append('\t');	
//			}
//		}
//		return sb.toString();

		// if user called hasNext but not next... then something will be wrong... <== should be fixed.
		int countTab = 0;
		for (int i = 0; i < currentLine.length(); i++) {
			if (currentLine.charAt(i) == '\t') {
				countTab++;
			}
			if (countTab ==	altIndex+1) {
				return currentLine.substring(i+1);
			}
		}
		return "";
	}
	
	public String readLine() {
		return currentLine;
	}	
}

//Other info:
/* 
* For completeness, VCF records are dynamically typed, so whether a VCF record is a SNP, Indel, Mixed,
*  or Reference site depends on the properties of the alleles in the record.
*  
*  Important! distinguish example variation in VCF records vs variation from the reference
*  
*
*  The encoding of structural variants in VCF is guided by two principles:
*  a) When breakpoints / alleles of structural variants are precisely known,
*  then the format should be completely compatible with the format used for smaller indels.
*  b) When the position, length and/or base composition of the variant is not known,
*  we want to encode as much useful information as possible about the variant.
* 
*  For precisely known variants, the REF and ALT fields should contain the full sequences for the alleles,
*   following the usual VCF conventions. For imprecise variants, 
*   the REF field may contain a single base and the ALT fields should contain symbolic alleles (e.g. <ID>)
*  Imprecise variants should also be marked by the presence of an IMPRECISE flag in the INFO field.
*/